package vip.liux.backend.application.serviceImpl.product;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.liux.application.dots.ListResultDto;
import vip.liux.backend.application.service.product.AutoMapperProfile;
import vip.liux.backend.application.service.product.CategoryDto;
import vip.liux.backend.application.service.product.CategoryService;
import vip.liux.backend.application.service.product.CreateCategoryDto;
import vip.liux.backend.infrastructure.code.BizCodeGenerator;
import vip.liux.contracts.models.product.Category;
import vip.liux.contracts.repositories.product.CategoryRepository;
import vip.liux.contracts.shared.enums.product.CategoryLevel;
import vip.liux.contracts.shared.enums.product.CategoryType;
import vip.liux.contracts.shared.value.LevelModel;
import vip.liux.core.exception.SystemException;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CategoryServiceImpl implements CategoryService {

    private final CategoryRepository categoryRepository;
    private final BizCodeGenerator bizCodeGenerator;

    public CategoryServiceImpl(CategoryRepository categoryRepository, BizCodeGenerator bizCodeGenerator) {
        this.categoryRepository = categoryRepository;
        this.bizCodeGenerator = bizCodeGenerator;
    }

    @Override
    public CategoryDto createCategory(CreateCategoryDto categoryDto) {
        Category category = AutoMapperProfile.INSTANCE.toEntity(categoryDto);
        Optional<Category> parentOptional = categoryRepository.findByCatNo(categoryDto.getParentNo());

        if (parentOptional.isPresent()) {
            Category parentCategory = parentOptional.get();
            if (parentCategory.getLevel() == CategoryLevel.THIRD) {
                throw new SystemException("父分类级别为第三级");
            }

            category.setLevel(CategoryLevel.getNext(parentCategory.getLevel()));
            category.setType(parentCategory.getType());
            category.setCatNo(category.getLevel() == CategoryLevel.SECOND ? bizCodeGenerator.generateSecondCatNo(parentCategory.getCatNo()) : bizCodeGenerator.generateThirdCatNo(parentCategory.getCatNo()));
        } else {
            category.setLevel(CategoryLevel.FIRST);
            category.setType(categoryDto.getType());
            category.setCatNo(bizCodeGenerator.generateFirstCatNo());
        }

        categoryRepository.save(category);

        return toDto(category);
    }

    @Override
    public ListResultDto<CategoryDto> getCategoryList(CategoryType type) {
        return new ListResultDto<>(
                LevelModel.buildTree(
                        categoryRepository.findByType(type).stream().map(this::toDto).toList(),
                        CategoryDto::getCatNo,
                        CategoryDto::getParentNo
                )
        );
    }

    @Override
    public CategoryDto getCategoryById(Long id) {
        Category category = categoryRepository.findById(id).orElseThrow(() -> new SystemException("未找到分类"));
        return toDto(category);
    }

    @Override
    public CategoryDto renameCategory(Long id, CreateCategoryDto categoryDto) {
        Category category = categoryRepository.findById(id).orElseThrow(() -> new SystemException("未找到分类"));
        category.setCatName(categoryDto.getCatName());
        category = categoryRepository.save(category);
        return toDto(category);
    }

    @Override
    public void deleteCategory(Long id) {
        if (categoryRepository.existsChildren(id)) {
            throw new SystemException("分类下存在子分类");
        }
        categoryRepository.deleteById(id);
    }

    @Override
    public CategoryDto getCategoriesOfAllParent(String catNo) {
        CategoryDto categoryDto = toDto(categoryRepository.findByCatNo(catNo)
                .orElseThrow(() -> new SystemException("未找到分类")));

        if (List.of(CategoryLevel.SECOND, CategoryLevel.THIRD).contains(categoryDto.getLevel())) {
            CategoryDto parent = getCategoriesOfAllParent(categoryDto.getParentNo());
            categoryDto.setParent(parent);
        }

        return categoryDto;
    }

    @Override
    public CategoryDto getCategoriesOfAllChildren(String catNo) {
        CategoryDto categoryDto = toDto(categoryRepository.findByCatNo(catNo)
                .orElseThrow(() -> new SystemException("未找到分类")));

        if (List.of(CategoryLevel.FIRST, CategoryLevel.SECOND).contains(categoryDto.getLevel())) {
            List<CategoryDto> children = getChildrenByParentNo(categoryDto.getCatNo());

            if (categoryDto.getLevel() == CategoryLevel.SECOND) {
                children.forEach(c -> c.setChildren(getChildrenByParentNo(c.getCatNo())));
            }

            categoryDto.setChildren(children);
        }
        return categoryDto;
    }

    @Override
    public List<CategoryDto> findByCatNos(List<String> nos) {
        Set<String> collect = nos.stream().filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        if (collect.isEmpty()) {
            return List.of();
        }
        return categoryRepository.findByCatNoIn(collect).stream().map(this::toDto).collect(Collectors.toList());
    }

    private List<CategoryDto> getChildrenByParentNo(String parentNo) {
        return categoryRepository.findByParentNo(parentNo).stream().map(this::toDto).collect(Collectors.toList());
    }


    private CategoryDto toDto(Category category) {
        return AutoMapperProfile.INSTANCE.toDto(category);
    }
}